package jmine.tec.hydra.services.incluir;

import jmine.tec.database.pack.PackException;
import jmine.tec.database.pack.services.PackEntityPersistenceHelper;
import jmine.tec.di.annotation.Injected;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.domain.senderRegistry.AbstractSenderRegistry;
import jmine.tec.hydra.domain.specification.HydraSpecificationImpl;
import jmine.tec.script.persistent.domain.Script;
import jmine.tec.services.annotations.Execution;
import jmine.tec.services.annotations.Input;
import jmine.tec.services.annotations.Output;
import jmine.tec.services.annotations.ServiceImplementor;
import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.api.export.ReferenceMap;
import jmine.tec.services.api.export.ServiceFiller;
import jmine.tec.services.export.impl.ExportUtils;
import jmine.tec.services.io.ServiceBean;

/**
 * Serviço de inclusão de uma especificação de integração.
 * 
 * @author piercio
 * @param <T> tipo de exportação
 */
@ServiceImplementor(action = ActionsEnum.INCLUIR)
public class HydraSpecificationService<T extends HydraSpecificationImpl> implements ServiceFiller<T> {

    public static final String IDENTIFICADOR = "Identificador";

    public static final String ACTION = "Ação";

    public static final String SYSTEM = "Sistema";

    public static final String SENDER = "Sender";

    public static final String ENCODE_SCRIPT = "Encode Script";

    public static final String DECODE_SCRIPT = "Decode Script";

    public static final String TEMPLATE_SCRIPT = "Template";

    public static final String DATABASE_ID = "Database ID";

    // Injected
    private PackEntityPersistenceHelper helper;

    // Obrigatórios
    private String action;

    private HydraSystem system;

    // Opcional
    private AbstractSenderRegistry sender;

    private Script encode;

    private Script template;

    private Script decode;

    private Long databaseID;

    /**
     * Executa o serviço e cria um {@link HydraSpecificationImpl}
     * 
     * @return uma especificação de integração.
     * @throws PackException PackException
     */
    @Execution
    @Output(propertyName = IDENTIFICADOR)
    public final HydraSpecificationImpl executeService() throws PackException {
        HydraSpecificationImpl spec = this.findOrCreate();
        spec.setAction(this.action);
        spec.setSystem(this.system);
        spec.setSenderRegistry(this.sender);
        spec.setEncodeScript(this.encode);
        spec.setTemplate(this.template);
        spec.setDecodeScript(this.decode);
        this.helper.save(spec, this.databaseID);
        return spec;
    }

    /**
     * @return bean
     * @throws PackException PackException
     */
    protected HydraSpecificationImpl findOrCreate() throws PackException {
        return this.helper.findOrCreate(HydraSpecificationImpl.class, this.databaseID, null);
    }

    /**
     * {@inheritDoc}
     */
    public void fillServiceBean(ServiceBean bean, ReferenceMap referenceMap, T entity) {
        ExportUtils.setService(bean, this.getClass());
        ExportUtils.put(bean, IDENTIFICADOR, referenceMap.addReference(entity, "hydraSpecification"));
        ExportUtils.put(bean, ACTION, entity.getAction());
        ExportUtils.put(bean, SYSTEM, referenceMap, entity.getSystem(), entity.getSystem().getMnemonico());
        ExportUtils.putDatabaseId(bean, DATABASE_ID, entity);
        if (entity.getSenderRegistry() != null) {
            ExportUtils.put(bean, SENDER, referenceMap, entity.getSenderRegistry(), entity.getSenderRegistry().getMnemonico());
        }
        if (entity.getEncodeScript() != null) {
            ExportUtils.put(bean, ENCODE_SCRIPT, entity.getEncodeScript().getMnemonico());
        }
        if (entity.getDecodeScript() != null) {
            ExportUtils.put(bean, DECODE_SCRIPT, entity.getDecodeScript().getMnemonico());
        }
        if (entity.getTemplate() != null) {
            ExportUtils.put(bean, TEMPLATE_SCRIPT, entity.getTemplate().getMnemonico());
        }
    }

    /**
     * @return the action
     */
    protected String getAction() {
        return this.action;
    }

    /**
     * @return the system
     */
    protected HydraSystem getSystem() {
        return this.system;
    }

    /**
     * @return the databaseID
     */
    protected Long getDatabaseID() {
        return this.databaseID;
    }

    /**
     * @return the helper
     */
    protected PackEntityPersistenceHelper getHelper() {
        return this.helper;
    }

    /**
     * @param helper the helper to set
     */
    @Injected
    public void setHelper(PackEntityPersistenceHelper helper) {
        this.helper = helper;
    }

    /**
     * @param action a ação da especificação.
     */
    @Input(fieldName = ACTION)
    public void setAction(String action) {
        this.action = action;
    }

    /**
     * @param system o sistema da especificação.
     */
    @Input(fieldName = SYSTEM)
    public void setSystem(HydraSystem system) {
        this.system = system;
    }

    /**
     * @param sender the sender to set
     */
    @Input(fieldName = SENDER, required = false)
    public void setSender(AbstractSenderRegistry sender) {
        this.sender = sender;
    }

    /**
     * @param encode the encode to set
     */
    @Input(fieldName = ENCODE_SCRIPT, required = false)
    public void setEncode(Script encode) {
        this.encode = encode;
    }

    /**
     * @param template the template to set
     */
    @Input(fieldName = TEMPLATE_SCRIPT, required = false)
    public void setTemplate(Script template) {
        this.template = template;
    }

    /**
     * @param decode the decode to set
     */
    @Input(fieldName = DECODE_SCRIPT, required = false)
    public void setDecode(Script decode) {
        this.decode = decode;
    }

    /**
     * @param databaseID the databaseID to set
     */
    @Input(fieldName = DATABASE_ID, required = false)
    public void setDatabaseID(Long databaseID) {
        this.databaseID = databaseID;
    }
}
